import type { AxiosRequestConfig } from "axios";
import axios from "axios";
import { ElNotification } from "element-plus";

import { useAuth } from "@/store/auth";

interface ResponseUtils<T> {
  code: number;
  data: T;
  message: string;
}

enum ResponseEnum {
  Success = 0,
  Login = 100702,
}

const responseCallbackMap: Record<number, () => void> = {
  [ResponseEnum.Login]: () => {
    useAuth().onOpenLoginPanel();
  },
};

const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_BASE_URL,
  timeout: 60000,
});

class Http {
  request<T>(config: AxiosRequestConfig) {
    if (config.headers && config.headers.responseType !== void 0) {
      config.responseType = config.headers.responseType;
    }

    config.headers = {
      ...(config.headers || {}),
      Token: useAuth().userToken,
    };

    return new Promise<T>((resolve, reject) => {
      axiosInstance<ResponseUtils<T>>(config)
        .then((res) => {
          if (res.data.code === ResponseEnum.Success) {
            resolve(res.data.data);
            return;
          }

          const callback = responseCallbackMap[res.data.code];
          if (callback) {
            callback();
          } else {
            ElNotification.error({
              message: res.data.message,
            });
          }
          reject(null);
        })
        .catch(() => {
          reject(null);
        });
    });
  }

  get<T>(
    url: string,
    params?: unknown,
    headers?: AxiosRequestConfig["headers"]
  ) {
    return this.request<T>({ method: "get", url, headers, params });
  }

  post<T>(
    url: string,
    data?: unknown,
    params?: unknown,
    headers?: AxiosRequestConfig["headers"]
  ) {
    return this.request<T>({ method: "post", url, headers, params, data });
  }

  put<T>(
    url: string,
    data?: unknown,
    params?: unknown,
    headers?: AxiosRequestConfig["headers"]
  ) {
    return this.request<T>({ method: "put", url, headers, params, data });
  }

  delete<T>(
    url: string,
    params?: unknown,
    data?: unknown,
    headers?: AxiosRequestConfig["headers"]
  ) {
    return this.request<T>({ method: "delete", url, headers, params, data });
  }
}

export const http = new Http();
